//===----------------------------------------------------------------------===//
//
//                         BusTub
//
// lock_manager.h
//
// Identification: src/include/concurrency/lock_manager.h
//
// Copyright (c) 2015-2019, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//
/*
 * 本实验需要支持事务的三种隔离级别
 * 1。READ_UNCOMMITED:只有在需要的时候写锁
 * 2。READ_COMMITED:要解决脏读的问题，解决方案：读时上读锁，读完解读锁；写时上写锁，但是要等到commit时才解写锁
 *          这样，永远不会读到没有commit的数据，因为上面有写锁
 * 3。REPEATABLE_READ：进一步打造可重复读锁。同一事务读两次数据的中途不想被其他事务的写干扰，这就需要巧妙的二段锁协议
 *           ：事务分为两个阶段（不考虑commit/abort），上锁阶段（GROWWING）只上锁，解锁阶段（SHNKING）只解锁。
 *           这样，第二次读取的时候，前一次读取的读锁一定还在，避免了中途被修改。
 *
 * */



/*
 * 死锁的预防：
 * 1。无论锁已经上了还是在等待中，所有请求都进入锁队列，并记录在事务的锁set中
 * 2。上锁请求均要完整的遍历一遍队列，每当结束wait状态时，均返回对应上锁函数的头部重新检查。
 * 3。id较小的为老事务，id较大的为新事务
 * 4。对于共享锁：老事务Abort新事务的排他锁；新事务则只等待老事务的排他锁解除，因为共享锁可以共存。
 * 5。对于排他锁：不进行等待，永远abort新事务
 * 6。对于锁升级：老事务abort新事务（无论新事务拥有任何锁），新事务等待老事务解除所有锁
 * 7。解锁后通知条件变量，选择notify_all()
 * 8.不要throw异常，有些测试用例没有考虑异常处理。对于需要abort的事务，直接设置状态并根据情况返回false或者继续有即可
 *
 * */

#pragma once

#include <algorithm>
#include <condition_variable>  // NOLINT
#include <list>
#include <memory>
#include <mutex>  // NOLINT
#include <unordered_map>
#include <utility>
#include <vector>

#include "common/config.h"
#include "common/rid.h"
#include "concurrency/transaction.h"
#include "transaction_manager.h"

namespace bustub {

class TransactionManager;

/**
 * LockManager handles transactions asking for locks on records.
 */
class LockManager {
  enum class LockMode { SHARED, EXCLUSIVE };

//  主要记录由发出该请求的txn_id,请求的是哪类的锁，以及该请求是否被授予
  class LockRequest {
   public:
    LockRequest(txn_id_t txn_id, LockMode lock_mode) : txn_id_(txn_id), lock_mode_(lock_mode), granted_(false) {}

    txn_id_t txn_id_;
    LockMode lock_mode_;
    bool granted_;
  };

//  跟踪哪些事务正在等待锁---一个LockQequestQueue中可能由一个或多个请求已经被授予锁
  class LockRequestQueue {
   public:
    std::list<LockRequest> request_queue_;
    // for notifying blocked transactions on this rid  用于通知此rid上被阻止的事务
    std::condition_variable cv_;
    // txn_id of an upgrading transaction (if any)  升级事务的txn\u id（如果有）
//    txn_id_t upgrading_ = INVALID_TXN_ID;
    bool upgrading_ = false;
  };

 public:
  /**
   * Creates a new lock manager configured for the deadlock prevention policy.
   */
  LockManager() = default;

  ~LockManager() = default;

  /*
   * [LOCK_NOTE]: For all locking functions, we:
   * 1. return false if the transaction is aborted; and
   * 2. block on wait, return true when the lock request is granted; and
   * 3. it is undefined behavior to try locking an already locked RID in the
   * same transaction, i.e. the transaction is responsible for keeping track of
   * its current locks.
   */

  /**
   * Acquire a lock on RID in shared mode. See [LOCK_NOTE] in header file.
   * @param txn the transaction requesting the shared lock
   * @param rid the RID to be locked in shared mode
   * @return true if the lock is granted, false otherwise
   */
//   Transaction txn试图对记录id RID获取一个共享锁.
//   这应该在等待时被阻塞,并且应该在授予时返回true.如果事务回滚(中止)返回false
  bool LockShared(Transaction *txn, const RID &rid);

  /**
   * Acquire a lock on RID in exclusive mode. See [LOCK_NOTE] in header file.
   * @param txn the transaction requesting the exclusive lock
   * @param rid the RID to be locked in exclusive mode
   * @return true if the lock is granted, false otherwise
   */

  //   Transaction txn试图对记录id RID获取一个排他锁
  //   这应该在等待时被阻塞,并且应该在授予时返回true.如果事务回滚(中止)返回false
  bool LockExclusive(Transaction *txn, const RID &rid);

  /**
   * Upgrade a lock from a shared lock to an exclusive lock.
   * @param txn the transaction requesting the lock upgrade
   * @param rid the RID that should already be locked in shared mode by the
   * requesting transaction
   * @return true if the upgrade is successful, false otherwise
   */

  //   Transaction txn试图对记录id RID将共享锁升级为排他锁
  //   这应该在等待时被阻塞,并且应该在授予时返回true.如果事务回滚(中止)返回false
  bool LockUpgrade(Transaction *txn, const RID &rid);

  /**
   * Release the lock held by the transaction.
   * @param txn the transaction releasing the lock, it should actually hold the
   * lock
   * @param rid the RID that is locked by the transaction
   * @return true if the unlock is successful, false otherwise
   */
//   解锁由事务持有的给定记录id标识的记录
  bool Unlock(Transaction *txn, const RID &rid);

 private:
/*
 * 将事务添加到等待队列中
 * lock_queue:等待队列中
 * txn_id:事务id
 * lock_mod:锁的类型
 * */
  inline void InsertTxnIntoLockQueue(LockRequestQueue *lock_queue,txn_id_t txn_id,LockMode lock_mod);

//  全局锁
  std::mutex latch_;

  /** Lock table for lock requests. 锁定请求的锁定表 */
// 存储了每个RID对应的LockRequestQueue队列。对于每个RID，也就是每个tuple，都有一个对应的锁请求队列LockRequestQueue
  std::unordered_map<RID, LockRequestQueue> lock_table_;
};

}  // namespace bustub
